package cn.huijielong.common.utils;

import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.codec.binary.Base64;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.sf.json.JSONObject;

public class SignUtil {

	public static Logger log = LoggerFactory.getLogger(SignUtil.class);

	/**
	 * 生成微信/支付宝的签名
	 * 
	 * @param map
	 *            需要签名的map
	 * 
	 * @return 返回签名
	 * 
	 * @throws Exception
	 *             出错抛出异常
	 */
	public static String getSign(Map<String, Object> map, String signKey) throws Exception {

		// 对map排序
		List<Map.Entry<String, Object>> infoIds = new ArrayList<Map.Entry<String, Object>>(map.entrySet());
		Collections.sort(infoIds, new Comparator<Map.Entry<String, Object>>() {
			@Override
			public int compare(Entry<String, Object> o1, Entry<String, Object> o2) {
				return o1.getKey().compareTo(o2.getKey());
			}
		});

		StringBuffer str = new StringBuffer();
		for (Map.Entry<String, Object> key : infoIds) {
			if (null != key.getValue() && !"".equals(key.getValue())) {
				str.append(key).append("&");
			}
		}
		str.append("key=").append(signKey);
		log.info("原始签名串:" + str.toString());
		String sign = GetMD5Code(str.toString()).toUpperCase();
		log.info("签名结果:"+sign);
		return sign;
	}

	/**
	 * 根据XML顺序签名
	 * @param content
	 * @param signKey
	 * @return
	 * @throws Exception
	 */
	public static String getSign(String xml, String signKey) throws Exception {
		SAXReader saxReader = new SAXReader();
		String signRes = null;
		try {
			Document doc = saxReader.read(xml);
			Element rootEle = doc.getRootElement();
			String key = null;
			String value = null;
			StringBuilder str = new StringBuilder();
			for (Iterator iter = rootEle.elementIterator(); iter.hasNext();) {
				Element e = (Element) iter.next();
				key = e.getName();
				value = e.getStringValue();
				if (null != value && !"".equals(value)&&!"sign".equals(value)) {
					str.append(key).append("=").append(value).append("&");
				}
			}
			str.append("key=").append(signKey);
			log.info("原始签名串:" + str.toString());
			signRes = GetMD5Code(str.toString()).toUpperCase();
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		return signRes;
	}

	public static boolean checkSign(String xml, String signKey) {
		log.info("-----开始校验签名-----");
		String localSign = null;
		JSONObject tmpJson = new JSONObject().fromObject(xml);
		String sign = tmpJson.getString("sign");
		try {
			localSign = getSign(xml, signKey);
			if (localSign.equals(sign)) {
				log.info("校验结果：签名合法");
				return true;
			}
		} catch (Exception e) {
			log.info("校验签名异常", e);
		}
		log.info("校验结果：签名不合法");
		log.info("-----结束校验签名-----");
		return false;
	}
	
	
	/**
	 * 验证数据签名
	 * 
	 * @param dataMap
	 * @param signKey
	 * @return
	 */
	public static boolean checkSign(Map<String, String> dataMap, String signKey) {
		log.info("-----开始校验签名-----");
		String sign;
		Map<String, Object> tempDataMap = new HashMap<>();
		tempDataMap.putAll(dataMap);
		if (tempDataMap.containsKey("sign")) {
			sign = (String) tempDataMap.get("sign");
			tempDataMap.remove("sign");
			String localSign = null;
			try {
				localSign = SignUtil.getSign(tempDataMap, signKey);
				if (localSign.equals(sign)) {
					log.info("校验结果：签名合法");
					return true;
				}
			} catch (Exception e) {
				log.info("校验签名异常", e);
			}
		}
		log.info("校验结果：签名不合法");
		log.info("-----结束校验签名-----");
		return false;
	}
	public static String getAliSign(Map<String, String> map, String priKey) throws Exception {
		Set<String> set = map.keySet();
		String[] keys = set.toArray(new String[0]);
		Arrays.sort(keys);
		StringBuilder sb = new StringBuilder();
		for (String key : keys) {
			sb.append(key).append("=").append(map.get(key)).append("&");
		}
		if (sb.length() > 0)
			sb.deleteCharAt(sb.length() - 1);

		PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(priKey));
		KeyFactory keyf = KeyFactory.getInstance("RSA");
		PrivateKey privateKey = keyf.generatePrivate(priPKCS8);
		Signature sign = Signature.getInstance("SHA1withRSA");
		sign.initSign(privateKey);
		byte[] data = sb.toString().getBytes("UTF-8");
		sign.update(data);
		byte[] signature = sign.sign();
		return Base64.encodeBase64String(signature);
	}

	/**
	 * md5加密
	 * 
	 * @param strObj
	 *            需要加密的字符串
	 * 
	 * @return 返回加密后的字符
	 */
	public static String GetMD5Code(String strObj) throws Exception {

		String resultString = null;
		try {
			resultString = new String(strObj);
			MessageDigest md = MessageDigest.getInstance("MD5");
			// md.digest() 该函数返回值为存放哈希值结果的byte数组
			resultString = byteToString(md.digest(strObj.getBytes("UTF-8")));
		} catch (NoSuchAlgorithmException e) {
			throw e;
		}
		return resultString;
	}

	private static String byteToString(byte[] bByte) {

		StringBuffer sBuffer = new StringBuffer();
		for (int i = 0; i < bByte.length; i++) {
			sBuffer.append(byteToArrayString(bByte[i]));
		}
		return sBuffer.toString();
	}

	private static String byteToArrayString(byte bByte) {

		String[] strDigits = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };

		int iRet = bByte;
		// System.out.println("iRet="+iRet);
		if (iRet < 0) {
			iRet += 256;
		}
		int iD1 = iRet / 16;
		int iD2 = iRet % 16;
		return strDigits[iD1] + strDigits[iD2];
	}
}
